package com.tlvip.io.bio;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;

/**
 * <p>文件描述：</p>
 * <p>版权所有： 版权所有(C)2016-2099</p>
 * <p>Life is short,we need passion</p>
 * <p>内容摘要： </p>
 * <p>其他说明： </p>
 * Date 2019-12-16</p>
 *
 * Author mac
 *
 * @version 1.0
 */
// 同步：ServerSocket单线程模式
// 阻塞：阻塞在accept与read上面
//      可以使用多线程处理socket达到异步非阻塞效果，但大量使用会严重消耗服务器资源，甚至宕机
public class SocketServer {
    public static void main(String[] args) throws IOException {
        ServerSocket serverSocket = new ServerSocket(9000);
        while (true) {
            System.out.println("等待连接。。");
            // 断点1，验证服务端被阻塞，等待客户端建立连接
            Socket socket = serverSocket.accept(); // 阻塞方法,阻塞在java.net.AbstractPlainSocketImpl.socketAccept
            System.out.println("有客户端连接了。。");
            // 无法支持大规模客户端连接，线程开启过多会严重损耗服务器性能
//            new Thread(() -> {
//                try {
//                    handler(socket);
//                } catch (IOException e) {
//                    e.printStackTrace();
//                }
//            }).start();
            handler(socket);
        }
    }

    private static void handler(Socket socket) throws IOException {
        System.out.println("thread id = " + Thread.currentThread().getId());
        byte[] bytes = new byte[1024];
        System.out.println("准备read。。");
        // 断点2，测试场景如下：
        // 1：没有数据可读时就阻塞
        // 2：客户端写入数据动作发生时，服务端被唤醒
        int read = socket.getInputStream().read(bytes);
        System.out.println("read完毕。。");
        if (read != -1) {
            System.out.println("接收到客户端的数据:" + new String(bytes, 0, read));
            System.out.println("thread id = " + Thread.currentThread().getId());
        }
        // 断点3，测试服务端写入数据，唤醒客户端read方法
        socket.getOutputStream().write("HelloClient".getBytes());
        socket.getOutputStream().flush();
        socket.close();
    }
}
